﻿using System;
using System.Collections.Generic;
using System.Runtime.Caching;

namespace CacheHelper
{
    /// <summary>
    /// 本地缓存处理器
    /// </summary>
    public class CacheAssistantor
    {
        private readonly MemoryCache _memoryCache = MemoryCache.Default;
        DateTime CurrentDateTime;

        #region 参数说明
        /*
         * 缓存是指可以进行高速数据交换的存储器，它先于内存与CPU交换数据，因此速率很快。
         * 由于CPU从内存中读取数据的速度比从磁盘读取快几个数量级，并且存在内存中，减小了数据库访问的压力， 所以缓存几乎每个项目都会用到
            
            MemoryCache.NoSlidingExpiration
            指示缓存项没有滑动过期时间
            Indicates that a cache entry has no Sliding expiration time 
        
            MemoryCache.InfiniteAbsoluteExpiration
            获取一个值，该值指示缓存项没有绝对过期
            Gets a value that indicates that a cache entry has no absolute expiration

            内存缓存过期时间有4种
            •永不过期•绝对过期时间•相对现在的过期时间•滑动过期时间
        */

        #endregion 参数说明

        public CacheAssistantor()
        {
            //_memoryCache = new MemoryCache("ecds");
        }

        public void Set(string key, object obj, int seconds = 7200)
        {
            //新建一个策略对象，该对象用于声明配置 对象在缓存中的处理策略
            var policy = new CacheItemPolicy
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(seconds)
            };
            //policy.RemovedCallback = new CacheEntryRemovedCallback(null);

            //NameValueCollection CacheSettings = new NameValueCollection(3);
            //CacheSettings.Add("cacheMemoryLimitMegabytes", Convert.ToString(_memoryCache));
            //CacheSettings.Add("pollingInterval", Convert.ToString("00:00:01"));
            //_memoryCache = new MemoryCache("TestCache", CacheSettings);

            //新建一个文件监视器对象，添加对资源文件的监视
            List<string> filePaths = new List<string>() { "c:/config.xml" };
            HostFileChangeMonitor monitor = new HostFileChangeMonitor(filePaths);
            //调用监视器的NotifyOnChanged方法，传入发生改变时的回调方法
            monitor.NotifyOnChanged(new OnChangedCallback(o => {
                _memoryCache.Remove(key);
            }));

            policy.ChangeMonitors.Add(monitor);

            //policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
            //DateTimeOffset a = new DateTimeOffset();
            //DateTimeOffset.Now
            //MemoryCacheEntryOptions
            //Set方法，会先检查是否存在key ，如果存在，更新value,不存在则创建。
            _memoryCache.Set(key, obj, DateTimeOffset.Now.AddSeconds(seconds));
        }

        public void Add(string key, object value, int seconds = 7200)
        {
            /*
             * MSCache提供了以下三种缓存过期的方式
             * 1、绝对到期（指定在一个固定的时间点到期）
             * 2、滑动到期（在一个时间长度内没有被命中则过期）
             * 3、到期Token（自定义过期）
             * 过期策略可以组合使用，如一小时自动过期+10分钟未访问过期
             * */
            var policy = new CacheItemPolicy
            {
                //截止日期 绝对过期时间 在指定时间后缓存被移除 比如短信码，设置三分钟后过期，三分钟后就会被移除
                AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(seconds),
                //按访问频度决定超期 某个缓存项在给定时段内未被访问，将被移除   如果对象一直被访问，则不会过期
                SlidingExpiration = TimeSpan.FromSeconds(seconds),
                //从缓存中移除某个项后将调用该委托 方便我们记日志或执行一些处理操作
                RemovedCallback = cacheItemRemoved,
                //从缓存中移除某个缓存项之前将调用该委托 方便我们记日志或执行一些处理操作
                UpdateCallback = null,
                //缓存项的优先级 NotRemovable 永不删除 Default 表示无优先级
                Priority = CacheItemPriority.NotRemovable
            };
            CacheItem CI = new CacheItem(key, value);
            _memoryCache.Add(CI, policy);

            Console.WriteLine(_memoryCache.GetCount());
        }

        void cacheItemRemoved(CacheEntryRemovedArguments arguments)
        {
            System.Diagnostics.Debug.WriteLine("Item removed from cache: {0} at {1}", arguments.CacheItem.Key, DateTime.Now.ToString());
        }

        public void Put(string key, object obj, int seconds = 7200)
        {
            _memoryCache.AddOrGetExisting(key, obj, DateTimeOffset.Now.AddSeconds(seconds));
        }

        public void OnGet()
        {
            CurrentDateTime = DateTime.Now;

            //if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
            //{
            //    cacheValue = CurrentDateTime;

            //    var cacheEntryOptions = new MemoryCacheEntryOptions()
            //        .SetSlidingExpiration(TimeSpan.FromSeconds(3));

            //    _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
            //}

            //CacheCurrentDateTime = cacheValue;
        }

        public T Get<T>(string key) where T : class
        {
            //var cache = MemoryCache.Default;
            try
            {
                return (T)_memoryCache[key];
            }
            catch (Exception)
            {
                return null;
            }
        }

        public void Remove(string key)
        {
            MemoryCache.Default.Remove(key);
        }

        public void Clear()
        {
            foreach (var item in _memoryCache)
            {
                this.Remove(item.Key);
            }
        }
    }
}
